#!/usr/bin/env python3
"""
归一化计算逻辑详细讲解
"""

def explain_normalization_logic():
    """
    详细讲解归一化计算逻辑
    """
    print("=" * 60)
    print("归一化计算逻辑详细讲解")
    print("=" * 60)
    
    print("\n1. 为什么需要归一化？")
    print("-" * 40)
    print("在混合检索系统中，我们有两个不同的分数系统：")
    print("• Elasticsearch (ES): 基于TF-IDF/BM25算法，分数范围很大 (如 0-100+)")
    print("• ChromaDB: 基于余弦相似度，分数范围固定 (0-1)")
    print("\n问题：如果直接相加，ES分数会完全压倒ChromaDB分数！")
    print("解决方案：将两个系统的分数都归一化到[0,1]范围内")
    
    print("\n2. Min-Max归一化公式")
    print("-" * 40)
    print("归一化公式：normalized = (score - min_score) / (max_score - min_score)")
    print("结果范围：始终在[0, 1]之间")
    print("• 最小值 → 0")
    print("• 最大值 → 1") 
    print("• 中间值 → 按比例映射")
    
    print("\n3. 代码逻辑分析")
    print("-" * 40)
    print("def normalize_scores(results, score_key):")
    print("    # 步骤1: 检查结果是否为空")
    print("    if not results:")
    print("        return {}")
    print("    ")
    print("    # 步骤2: 提取所有分数")
    print("    scores = [r.get(score_key, 0.0) for r in results]")
    print("    ")
    print("    # 步骤3: 找到最小值和最大值")
    print("    min_score = min(scores)")
    print("    max_score = max(scores)")
    print("    ")
    print("    # 步骤4: 处理特殊情况（所有分数相同）")
    print("    if max_score - min_score < 1e-9:")
    print("        return {i: 1.0 for i in range(len(results))}")
    print("    ")
    print("    # 步骤5: 执行归一化计算")
    print("    return {i: (s - min_score) / (max_score - min_score) for i, s in enumerate(scores)}")


def demonstrate_calculation():
    """
    演示具体的计算过程
    """
    print("\n4. 具体计算演示")
    print("-" * 40)
    
    # 模拟ES分数
    es_scores = [15.2, 8.7, 22.1, 12.3]
    print(f"ES原始分数: {es_scores}")
    
    # 计算归一化
    min_es = min(es_scores)
    max_es = max(es_scores)
    print(f"最小值: {min_es}, 最大值: {max_es}")
    print(f"分数范围: {max_es - min_es}")
    
    print("\n归一化计算过程:")
    es_normalized = []
    for i, score in enumerate(es_scores):
        norm_score = (score - min_es) / (max_es - min_es)
        es_normalized.append(norm_score)
        print(f"  索引{i}: ({score} - {min_es}) / ({max_es} - {min_es}) = {norm_score:.3f}")
    
    print(f"\nES归一化结果: {[round(x, 3) for x in es_normalized]}")
    
    # 模拟ChromaDB分数
    chroma_scores = [0.85, 0.72, 0.91, 0.68]
    print(f"\nChromaDB原始分数: {chroma_scores}")
    
    min_chroma = min(chroma_scores)
    max_chroma = max(chroma_scores)
    print(f"最小值: {min_chroma}, 最大值: {max_chroma}")
    print(f"分数范围: {max_chroma - min_chroma}")
    
    print("\n归一化计算过程:")
    chroma_normalized = []
    for i, score in enumerate(chroma_scores):
        norm_score = (score - min_chroma) / (max_chroma - min_chroma)
        chroma_normalized.append(norm_score)
        print(f"  索引{i}: ({score} - {min_chroma}) / ({max_chroma} - {min_chroma}) = {norm_score:.3f}")
    
    print(f"\nChromaDB归一化结果: {[round(x, 3) for x in chroma_normalized]}")


def demonstrate_fusion():
    """
    演示融合计算过程
    """
    print("\n5. 融合计算演示")
    print("-" * 40)
    
    # 模拟归一化后的分数
    es_norm = [0.485, 0.000, 1.000, 0.269]
    chroma_norm = [0.739, 0.174, 1.000, 0.000]
    
    # 权重设置
    weight_es = 0.6
    weight_chroma = 0.4
    
    print(f"权重设置: ES={weight_es}, ChromaDB={weight_chroma}")
    print("\n融合计算过程:")
    
    fused_scores = []
    for i in range(len(es_norm)):
        fused = weight_es * es_norm[i] + weight_chroma * chroma_norm[i]
        fused_scores.append(fused)
        print(f"  索引{i}: {weight_es}×{es_norm[i]:.3f} + {weight_chroma}×{chroma_norm[i]:.3f} = {fused:.3f}")
    
    print(f"\n融合结果: {[round(x, 3) for x in fused_scores]}")


def explain_edge_cases():
    """
    解释边界情况处理
    """
    print("\n6. 边界情况处理")
    print("-" * 40)
    
    print("情况1: 所有分数相同")
    same_scores = [5.0, 5.0, 5.0]
    print(f"分数: {same_scores}")
    print("问题: max_score - min_score = 0，会导致除零错误")
    print("解决: 检查差值是否小于1e-9，如果是则返回1.0")
    print("结果: {0: 1.0, 1: 1.0, 2: 1.0}")
    
    print("\n情况2: 空结果")
    print("分数: []")
    print("问题: 没有分数可以归一化")
    print("解决: 直接返回空字典{}")
    
    print("\n情况3: 只有一个分数")
    single_score = [10.5]
    print(f"分数: {single_score}")
    print("问题: max_score - min_score = 0")
    print("解决: 同样返回1.0")


def explain_benefits():
    """
    解释归一化的好处
    """
    print("\n7. 归一化的好处")
    print("-" * 40)
    
    print("✓ 公平竞争: 两个系统的分数在相同范围内比较")
    print("✓ 可控权重: 通过权重参数控制不同系统的影响")
    print("✓ 稳定性: 不受原始分数范围影响")
    print("✓ 可解释性: 所有分数都在[0,1]范围内，便于理解")
    print("✓ 灵活性: 可以轻松调整权重以适应不同场景")


def main():
    """
    主函数
    """
    explain_normalization_logic()
    demonstrate_calculation()
    demonstrate_fusion()
    explain_edge_cases()
    explain_benefits()
    
    print("\n" + "=" * 60)
    print("归一化逻辑讲解完成！")
    print("=" * 60)


if __name__ == "__main__":
    main()
